package com.common.security.config;



import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.common.core.base.entity.SysMenu;
import com.common.core.base.entity.SysRole;
import com.common.core.constant.RoleNameConstant;
import com.common.security.db.repository.SysMenuRepo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    AntPathMatcher antPathMatcher = new AntPathMatcher(); // AntPathMatcher主要用于实现蚂蚁风格的URL匹配。

    @Resource
    SysMenuRepo sysMenuRepo;

    // Spring Security使用FilterInvocationSecurityMetadataSource接口中的getAttributes方法来确定请求需要哪些角色@以（权力）否决
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        /*
         * 此方法的参数是FilterInvocation。开发人员可以从FilterInvocation中提取当前请求的URL。
         * 返回值为Collection<ConfigAttribute>，表示当前请求URL所需的角色。
         */
        FilterInvocation invocation = (FilterInvocation) object;
        String requestUrl = invocation.getRequestUrl();
        /*
         * 从数据库中获取所有资源信息，即本例中的菜单表和菜单对应的角色，
         * 在真实的项目环境中，开发人员可以将资源信息缓存在Redis或其他缓存数据库中。
         */
        List<SysMenu> allMenus = sysMenuRepo.getAllMenus();
        // 遍历资源信息。在遍历过程中，获取当前请求的URL所需的角色信息并返回。
        for (SysMenu menu : allMenus) {
            if (antPathMatcher.match(menu.getPath(), requestUrl)) {
                JSONArray roleJSON = menu.getRoles();
                List<SysRole> roles = roleJSON.stream()
                        .map(item -> JSONObject.parseObject(item.toString(), SysRole.class))
                        .collect(Collectors.toList());
                String[] roleArr = new String[roles.size()];
                for (int i = 0; i < roleArr.length; i++) {
                    String name = roles.get(i).getRoleName();
                    if (StringUtils.isNotBlank(name)) {
                        roleArr[i] = roles.get(i).getRoleName();
                    }
                }
                return SecurityConfig.createList(roleArr);
            }
        }
        // 如果当前请求的URL在资源表中没有相应的模式，则假设登录后可以访问该请求，即直接返回ROLE_LOGIN。
        return SecurityConfig.createList(RoleNameConstant.LOGIN);
    }

    /**
     * getAllConfigAttributes方法用于返回所有已定义的权限资源。启动时，SpringSecurity将验证相关配置是否正确。
     * 如果不需要验证，此方法可以直接返回null。
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    /**
     * supports方法返回类对象是否支持验证。
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}